package com.chukun.multi.activeobject;

import org.apache.log4j.Logger;

import java.io.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author chukun
 *  磁盘保存操作
 */
public class DiskbasedRequestPersistence implements RequestPersistence {

    // 负责缓存文件的存储管理
    private final SectionBasedDiskStorage storage = new SectionBasedDiskStorage();
    private final Logger logger = Logger.getLogger(DiskbasedRequestPersistence.class);

    @Override
    public void store(MMSDeliveryRequest request) {
        // 申请缓存文件的文件名
        String[] fileNameParts = storage.apply4Filename(request);
        File file = new File(fileNameParts[0]);
        try {
            ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(file));
        } catch (IOException e) {
            storage.decrementSectionFileCount(fileNameParts[1]);
            logger.error("fail to store request ", e);
        }

    }
}

/**
 * 操作文件目录
 */
class SectionBasedDiskStorage {

    private Deque<String> sectionNames = new LinkedList<>();

    /**
     *  存储子目录名---> 子目录下缓存文件的计数器
     */
    private Map<String, AtomicInteger> sectionFileCountMap = new HashMap<>();

    private int maxFilesPerSection = 2000;
    private int maxSectionCount = 100;

    private final String storageBaseDir = System.getProperty("user.dir") + "/vpn";

    private final Object sectionLock = new Object();

    public String[] apply4Filename(MMSDeliveryRequest request) {
        String sectionName;
        int iFileCount;
        boolean need2RemoveSection = false;
        String[] fileName = new String[2];
        synchronized (sectionLock) {
            // 获取当前的存储子目录
            sectionName = this.getSectionName();
            AtomicInteger fileCount = sectionFileCountMap.get(sectionName);
            iFileCount = fileCount.get();
            // 当前存储子目录已满
            if (iFileCount >= maxFilesPerSection) {
                if (sectionNames.size() >= maxSectionCount) {
                    need2RemoveSection = true;
                }
                // 创建新的存储子目录
                sectionName = this.makeNewSectionDir();
                fileCount = sectionFileCountMap.get(sectionName);
            }
            iFileCount = fileCount.get();
        }
        fileName[0] = storageBaseDir + "/" + sectionName + "/"
                + new DecimalFormat("0000").format(iFileCount)
                + "-" + request.getTimeStamp().getTime() / 1000 + "-" + request.getExpiry()
                + ".rq";
        fileName[1] = sectionName;
        if (need2RemoveSection) {
            // 删除最老的存储子目录
            String oldestSectionName = sectionNames.removeFirst();
            this.removeSection(oldestSectionName);
        }
        return fileName;
    }

    /**
     * 减少该目录下的文件数量
     * @param sectionName
     */
    public void decrementSectionFileCount(String sectionName) {
        AtomicInteger fileCount = sectionFileCountMap.get(sectionName);
        if (!Objects.isNull(fileCount)) {
            fileCount.decrementAndGet();
        }
    }

    /**
     * 删除目录，以及当前目录下的所有文件
     * @param sectionName
     * @return
     */
    private boolean removeSection(String sectionName) {
        boolean result = true;
        File dir = new File(storageBaseDir + "/" + sectionName);
        for (File file : dir.listFiles()) {
            result = result && file.delete();
        }
        result = result && dir.delete();
        return result;
    }


    /**
     * 获取目录名称
     * @return
     */
    private String getSectionName() {
        String sectionName;
        if (sectionNames.isEmpty()) {
            sectionName = this.makeNewSectionDir();
        } else {
            sectionName = sectionNames.getLast();
        }
        return sectionName;
    }

    /**
     * 创建目录
     * @return
     */
    private String makeNewSectionDir() {
        String sectionName;
        SimpleDateFormat dtf = new SimpleDateFormat("MMddHHmmss");
        sectionName = dtf.format(new Date());
        File dir = new File(storageBaseDir + "/" + sectionName);
        if (dir.mkdir()) {
            sectionNames.addLast(sectionName);
            sectionFileCountMap.put(sectionName, new AtomicInteger(0));
        } else {
            throw new RuntimeException("can not create section dir " + sectionName);
        }
        return sectionName;
    }

}
